package com.ybzl.gateway.timer;


import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.ybzl.gateway.config.EmqxConfig;
import com.ybzl.gateway.domain.NoIbeacon;
import com.ybzl.gateway.domain.vo.DeviceInfoVO;
import com.ybzl.gateway.domain.DeviceStatusInfo;
import com.ybzl.gateway.service.IDeviceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Component
@Slf4j
public class DeviceStatusTimer {

    @Autowired
    private IDeviceService deviceService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;


    /**
     * 定时修改设备状态
     */
//    @Scheduled(cron = "0 0/5 * * * ?")
    public void updateStatus() {
        log.info("获取基站心跳开始执行");
        // 1.查询设备id分组查询设备记录表中
        List<Map<String, Object>> deviceInfoList = deviceService.selectDeviceInfoByMinute();

        // 2.查询心跳分组查询设备记录
        List<String> heartbeatList = deviceService.selectHeartbeatByMinute();
        Map<String, String> ipMap = heartbeatList.stream().collect(Collectors.toMap(k -> k, v -> v, (k1, k2) -> k1));

        // 离线的设备数据
        List<DeviceStatusInfo> statusList = new ArrayList<>();
        if (heartbeatList.size() > 0) {
            for (int i = 0; i < deviceInfoList.size(); i++) {
                Map<String, Object> deviceMap = deviceInfoList.get(i);
                if (StringUtils.isEmpty(ipMap.get(deviceMap.get("ip")))) {
                    // 说明当前设备已经超过5分钟没有上传数据了
                    statusList.add(new DeviceStatusInfo((String) deviceMap.get("ex_id"), (String) deviceMap.get("ip"), 0));
                    deviceInfoList.remove(deviceInfoList.get(i));
                }
            }

            /**
             *  设备的记录状态
             */
            for (Map<String, Object> deviceMap : deviceInfoList) {
                statusList.add(new DeviceStatusInfo((String) deviceMap.get("ex_id"), (String) deviceMap.get("ip"), 1));
            }
        } else {
            for (int i = 0; i < deviceInfoList.size(); i++) {
                Map<String, Object> deviceMap = deviceInfoList.get(i);
                if (StringUtils.isEmpty(ipMap.get(deviceMap.get("ip")))) {
                    // 说明当前设备已经超过5分钟没有上传数据了
                    statusList.add(new DeviceStatusInfo((String) deviceMap.get("ex_id"), (String) deviceMap.get("ip"), 0));
                }
            }
        }

        // 3.进行数据入库
        deviceService.insertDeviceStatus(statusList);
        EmqxConfig.push("location/status", false
                , statusList);
        log.info("获取基站心跳结束执行");
    }

    /**
     * 每秒推送设备实时状态
     */
    @Scheduled(cron = "0/1 * * * * ?")
    public void pushLocation() {
        long time = DateUtil.date().getTime();
        HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
        Map<String, String> entries = hashOperations.entries("location::map");
        for (String str : entries.values()) {
            DeviceInfoVO deviceInfo = JSONObject.parseObject(str, DeviceInfoVO.class);
            long diff = Math.abs(time - deviceInfo.getTs());
            if (diff < 1000 * 3) {
                EmqxConfig.push("locationWeb", false, deviceInfo);
            } else {
                hashOperations.delete("location::map", deviceInfo.getTagId());
            }
        }
    }


//    @Scheduled(cron = "0/3 * * * * ?")
    public void getNoIbeacon() {
        List<NoIbeacon> noIbeaconList = deviceService.selectNoIbeacon();
        if (noIbeaconList.size() > 0) {
            // 根据标签进行分组
            Map<String, List<NoIbeacon>> noIbeaconExIdMap = noIbeaconList.stream()
                    .collect(Collectors.groupingBy(NoIbeacon::getTagId, TreeMap::new, Collectors.toList()));

            List<NoIbeacon> tempList = new ArrayList<>();
            for (String tagId : noIbeaconExIdMap.keySet()) {
                // 对基站进行分组 一个标签对应多个基站
                Map<String, List<NoIbeacon>> exIdMap = noIbeaconExIdMap.get(tagId)
                        .stream().collect(Collectors.groupingBy(NoIbeacon::getExId, TreeMap::new, Collectors.toList()));

                for (String exId : exIdMap.keySet()) {
                    // 在同一个标签下对基站进行分组 获取型号强度最强的一个
                    List<NoIbeacon> collect = exIdMap.get(exId).stream().sorted(Comparator.comparing(NoIbeacon::getRssi).reversed()).collect(Collectors.toList());
                    tempList.add(collect.get(0));
                }
            }

            // 最终的集合数据
            Map<String, List<NoIbeacon>> tempListMap = tempList.stream()
                    .collect(Collectors.groupingBy(NoIbeacon::getTagId, TreeMap::new, Collectors.toList()));

            for (String tagId : tempListMap.keySet()) {
                List<NoIbeacon> collect = tempListMap.get(tagId).stream()
                        .sorted(Comparator.comparing(NoIbeacon::getRssi).reversed()).collect(Collectors.toList());

                // 获取每个基站下最强的一个标签数据
                NoIbeacon currentNoIbeacon = collect.get(0);

                String noibeaconStr = (String) redisTemplate.opsForValue().get("noibeacon::tagId::" + currentNoIbeacon.getTagId());
                if (StringUtils.isEmpty(noibeaconStr)) {
                    // 第一次出现直接推送
                    // 推送当前标签数据
                    EmqxConfig.push("noibeacon", false, currentNoIbeacon);
                    redisTemplate.opsForValue().set("noibeacon::tagId::" + currentNoIbeacon.getTagId(), JSONObject.toJSONString(currentNoIbeacon));
                } else {
                    // 不是第一次出现
                    // 获取上一次的数据
                    NoIbeacon existNoIbecon = JSONObject.parseObject(noibeaconStr, NoIbeacon.class);

                    if (currentNoIbeacon.getExId().equals(existNoIbecon.getExId())) {
                        // 当前最大的和上一次基站id一样
                        // 直接推送
                        EmqxConfig.push("noibeacon", false, currentNoIbeacon);
                    } else {
                        // 当前最大的和上一次基站id不一样
                        // 判断当前tempList里面是否包含上次基站id
                        List<NoIbeacon> existExIdList = tempList.stream().filter(t -> t.getExId().equals(existNoIbecon.getExId()) && t.getTagId().equals(existNoIbecon.getTagId()))
                                .collect(Collectors.toList());

                        if (existExIdList.size() > 0) {
                            // 根据上一次的标签id和基站id获取最新的数据
                            // 从当前的tempList里面通过上一次的tagId和exId获取最新的数据值
                            List<NoIbeacon> noIbeacons = tempList.stream()
                                    .filter(t -> t.getTagId().equals(existNoIbecon.getTagId()) && t.getExId().equals(existNoIbecon.getExId())).collect(Collectors.toList());

                            if (noIbeacons.size() > 0) {
                                NoIbeacon noIbeacon = noIbeacons.get(0);
                                if (currentNoIbeacon.getRssi() - noIbeacon.getRssi() >= 10) {
                                    // 变化了
                                    // 推送当前的currentNoIbeacon
                                    EmqxConfig.push("noibeacon/change", false, currentNoIbeacon);
                                    // 更新
                                    redisTemplate.opsForValue().set("noibeacon::tagId::" + currentNoIbeacon.getTagId(), JSONObject.toJSONString(currentNoIbeacon));
                                } else {
                                    // 推送上一次的数据
                                    EmqxConfig.push("noibeacon", false, existNoIbecon);
                                }
                            }
                        } else {
                            // 不包含 说明新的一批数据里面没有之前的tagId和exId说明 已经移动了位置
                            // 根据之前的id和基站进行判断
                            String containStr = (String) redisTemplate.opsForValue().get("noibeacon::contain::" + existNoIbecon.getTagId() + "_" + existNoIbecon.getExId());
                            if (StringUtils.isEmpty(containStr)) {
                                redisTemplate.opsForValue().set("noibeacon::contain::" + existNoIbecon.getTagId() + "_" + existNoIbecon.getExId(), String.valueOf(1));
                            } else {
                                Integer count = Integer.valueOf(containStr);
                                if (count > 2) {
                                    // 推送当前最强的数据
                                    EmqxConfig.push("noibeacon/change", false, currentNoIbeacon);
                                    // 更新
                                    redisTemplate.opsForValue().set("noibeacon::tagId::" + currentNoIbeacon.getTagId(), JSONObject.toJSONString(currentNoIbeacon));
                                    redisTemplate.delete("noibeacon::contain::" + existNoIbecon.getTagId() + "_" + existNoIbecon.getExId());
                                } else {
                                    redisTemplate.opsForValue().set("noibeacon::contain::" + existNoIbecon.getTagId() + "_" + existNoIbecon.getExId(), String.valueOf(count++));
                                }
                            }


                        }
                    }
                }
            }
        }
    }

//  多个以基站为主
//    public void getNoIbeacon() {
//        List<NoIbeacon> noIbeaconList = deviceService.selectNoIbeacon();
//        if (noIbeaconList.size() > 0) {
//            Map<String, List<NoIbeacon>> noIbeaconExIdMap = noIbeaconList.stream()
//                    .collect(Collectors.groupingBy(NoIbeacon::getExId, TreeMap::new, Collectors.toList()));
//            List<NoIbeacon> tempList = new ArrayList<>();
//            for (String exId : noIbeaconExIdMap.keySet()) {
//                tempList.add(noIbeaconExIdMap.get(exId).get(0));
//            }
//            List<NoIbeacon> compareList = tempList.stream().sorted(Comparator.comparing(NoIbeacon::getRssi).reversed())
//                    .collect(Collectors.toList());
//            for (NoIbeacon ibeacon : compareList) {
//                // 每次更新都更新对应的基站
//                redisTemplate.opsForValue().set("noibeacon::ex::" + ibeacon.getExId() + "::" + ibeacon.getTagId(), JSONObject.toJSONString(ibeacon));
//            }
//            System.out.println("=================================");
//            System.out.println(compareList);
//            System.out.println("=================================");
//            for (NoIbeacon currentNoIbeacon : compareList) {
//                String noibeaconStr = (String) redisTemplate.opsForValue().get("noibeacon::" + currentNoIbeacon.getTagId());
//                if (StringUtils.isEmpty(noibeaconStr)) {
//                    redisTemplate.opsForValue().set("noibeacon::" + currentNoIbeacon.getTagId(), JSONObject.toJSONString(currentNoIbeacon));
//                } else {
//                    /**
//                     * 获取上次的数据，但是上次数据的的rssi是有改变的
//                     */
//                    NoIbeacon existIbeacon = JSONObject.parseObject(noibeaconStr, NoIbeacon.class);
//                    String existIbeaconStr = (String) redisTemplate.opsForValue().get("noibeacon::ex::" + existIbeacon.getExId() + "::" + existIbeacon.getTagId());
//                    existIbeacon.setRssi(JSONObject.parseObject(existIbeaconStr, NoIbeacon.class).getRssi());
//                    if (currentNoIbeacon.getRssi() - existIbeacon.getRssi() >= 5) {
//                        if (!currentNoIbeacon.getExId().equals(existIbeacon.getExId())) {
//                            EmqxConfig.push("noibeacon/change", false, currentNoIbeacon);
//                            // 进行推送更新新的数据
//                            redisTemplate.opsForValue().set("noibeacon::" + currentNoIbeacon.getTagId(), JSONObject.toJSONString(currentNoIbeacon));
//                        }
//                    }
//                    if(currentNoIbeacon.getTagId().equals(existIbeacon.getTagId()) && currentNoIbeacon.getExId().equals(existIbeacon.getExId())){
//                        EmqxConfig.push("noibeacon", false, currentNoIbeacon);
//                    }
//
//                    if(currentNoIbeacon.getTagId().equals(existIbeacon.getTagId()) && !currentNoIbeacon.getExId().equals(existIbeacon.getExId())){
//                        if (currentNoIbeacon.getRssi() - existIbeacon.getRssi() >= 5) {
//                            EmqxConfig.push("noibeacon", false, currentNoIbeacon);
//                        }
//                    }
//
//                }
//            }
//        }
//    }
//    单个是好的
//    public void getNoIbeacon() {
//        List<NoIbeacon> noIbeaconList = deviceService.selectNoIbeacon();
//        if (noIbeaconList.size() > 0) {
//            Map<String, List<NoIbeacon>> noIbeaconExIdMap = noIbeaconList.stream()
//                    .collect(Collectors.groupingBy(NoIbeacon::getExId, TreeMap::new, Collectors.toList()));
//            List<NoIbeacon> tempList = new ArrayList<>();
//            for (String exId : noIbeaconExIdMap.keySet()) {
//                tempList.add(noIbeaconExIdMap.get(exId).get(0));
//            }
//            List<NoIbeacon> compareList = tempList.stream().sorted(Comparator.comparing(NoIbeacon::getRssi).reversed())
//                    .collect(Collectors.toList());
//            for (NoIbeacon ibeacon : compareList) {
//                // 每次更新都更新对应的基站
//                redisTemplate.opsForValue().set("noibeacon::ex::" + ibeacon.getExId(), JSONObject.toJSONString(ibeacon));
//            }
//
//            // 获取信号强度最强的一个
//            NoIbeacon currentNoIbeacon = compareList.get(0);
//
//            String noibeaconStr = (String) redisTemplate.opsForValue().get("noibeacon::" + currentNoIbeacon.getTagId());
//            if (StringUtils.isEmpty(noibeaconStr)) {
//                redisTemplate.opsForValue().set("noibeacon::" + currentNoIbeacon.getTagId(), JSONObject.toJSONString(currentNoIbeacon));
//            } else {
//                /**
//                 * 获取上次的数据，但是上次数据的的rssi是有改变的
//                 */
//                NoIbeacon existIbeacon = JSONObject.parseObject(noibeaconStr, NoIbeacon.class);
//                String existIbeaconStr = (String) redisTemplate.opsForValue().get("noibeacon::ex::" + existIbeacon.getExId());
//                existIbeacon.setRssi(JSONObject.parseObject(existIbeaconStr, NoIbeacon.class).getRssi());
//                if (currentNoIbeacon.getRssi() - existIbeacon.getRssi() >= 5) {
//                    if (!currentNoIbeacon.getExId().equals(existIbeacon.getExId())) {
//                        EmqxConfig.push("noibeacon/change", false, currentNoIbeacon);
//                        // 进行推送更新新的数据
//                        redisTemplate.opsForValue().set("noibeacon::" + currentNoIbeacon.getTagId(), JSONObject.toJSONString(currentNoIbeacon));
//                    }
//                } else {
//                    EmqxConfig.push("noibeacon", false, currentNoIbeacon);
//                }
//            }
//        }
//    }


    /**
     * 计算标签到基站的距离
     *
     * @param txPower 标签在1米处的RSSI值（单位：dBm）
     * @param rssi    基站接收到的信号强度（单位：dBm）
     * @param n       环境衰减因子（通常为2~4）
     * @return 距离（单位：米）
     */
    public static double calculateDistance(double txPower, double rssi, double n) {
        if (rssi == 0) {
            // 避免除以零导致的错误
            return Double.POSITIVE_INFINITY;
        }
        double ratio = (txPower - rssi) / (10 * n);
        return Math.pow(10, ratio);
    }
}
